package com.woniuxueyuan.service.impl;

import com.woniuxueyuan.entity.Book;
import com.woniuxueyuan.mapper.BookMapper;
import com.woniuxueyuan.service.BookService;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

@Service
public class BookServiceImpl implements BookService {

//    private StringRedisTemplate stringRedisTemplate;//=RedisTemplate<string,string> redisTemplate
    @Resource
    private RedisTemplate  redisTemplateInit; //默认 泛型RedisTemplate<object,object>
    @Resource
    private BookMapper bookMapper;

    //加锁
    ReentrantLock lock = new ReentrantLock();

    @Override
    public List<Book> queryAll() {
        return bookMapper.queryAll();
    }

    /**
     * 对该接口数据作缓存
     * redis基本数据类型有5种，String，hash，set，zset，list
     * string 类型的key默认最低会占512字节，超过会扩容512M
     * 有的缓存key，远远达不到512字节，如果缓存来了很多这样数据，有点浪费内存，可以用hash数据类型优化
     *
     *
     *
     * 缓存穿透
     * 定义：1；缓存空对象
     * 缺点：会产生很多垃圾数据，浪费内存
     *      2：利用布隆过滤器（本质就是redis的bitmap（很长的二进制数组）的数据类型实现的）
     *      缺点：会出现午盘
     *      优点：用布隆过滤器判断数据是否存在，只有一个bit标识，节约空间
     * @param id
     * @return
     */

    @Override
    public Book queryBookById(Integer id) {

        //查询redis中是否有对应缓存数据
        HashOperations hash = redisTemplateInit.opsForHash();
        Book cacheBook = (Book)hash.get("BOOKSERVICEIMPL:QUERYBYID",id+"");
        if(cacheBook !=null){
            return cacheBook;
      }
        boolean b = lock.tryLock();
        try {
            if (b) {
                Book book = bookMapper.queryBookById(id);
                //把数据库数据存入redis
                hash.put("BOOKSERVICEIMPL:QUERYBYID", id + "", book == null ? new Book() : book);
                redisTemplateInit.expire("BOOKSERVICEIMPL:QUERYBYID", 30, TimeUnit.DAYS);

                return book;

            }
            else {
                return null;  //没有获取到锁的线程
            }
        } finally {
            if(lock.isLocked() && lock.isHeldByCurrentThread())
                lock.unlock();//释放锁
        }
    }

    /**
     * 延迟双删解决数据一致性问题
     * @param book
     */
    public void updateBook(Book book){
        //1.删除缓存
//       redisTemplateInit.delete("key");//根据大key删除
//        redisTemplateInit.opsForHash().delete("大key","小key");

        //2:执行sql语句
        //调mapper

        //3:睡眠一会，睡眠时间根据查询方法运行时间决定
//        Thread.sleep(200);

        //4删除缓存






    }
}



//     //查询redis中是否有对应缓存数据
//        Book cacheBook = (Book) redisTemplateInit.opsForValue().get("BOOKSERVICEIMPL:QUERYBYID"+id);
//        if(cacheBook !=null){
//            return cacheBook;
//        }
//        Book book = bookMapper.queryBookById(id);
//        //把数据库数据存入redis
////        redisTemplateInit.opsForValue().set("BOOKSERVICEIMPL:QUERYBYID"+id,book);
//        redisTemplateInit.opsForValue().set("BOOKSERVICEIMPL:QUERYBYID"+id,book==null?new Book():book);
//        return book;
